package com.hs.live.user.service;

import com.hs.live.common.redis.utils.RedisLiveUtil;
import com.hs.live.common.util.ConvertBeanUtils;
import com.hs.live.user.dto.UserDTO;
import com.hs.live.user.entity.UserDO;
import com.hs.live.user.mapper.UserMapper;
import com.hs.live.common.redis.key.UserRedisKeyGenerate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * @Description: UserService类
 * @Author 胡尚
 * @Date: 2024/9/6 14:38
 */
@Slf4j
@Service
public class UserService {

    @Autowired
    UserMapper userMapper;

    @Autowired
    RedisLiveUtil redisUtil;

    /**
     * 根据UserId查询User信息
     * @param id userId
     * @return User数据
     */
    public UserDTO getUserById(Long id) {
        UserDTO userDTO = null;

        // 查询redis缓存
        String userInfoKey = UserRedisKeyGenerate.getUserInfoKey(id);
        userDTO = redisUtil.get(userInfoKey, UserDTO.class);
        //  缓存穿透的判断
        if (userDTO != null && userDTO.getUserId() < 0){
            log.debug("缓存穿透处理，从redis中查询到了空对象");
            return null;
        }

        // 缓存没有就查询DB 同时保存一份至缓存
        if (userDTO == null){
            // 根据id查询数据  查询DB可以通过添加分布式锁+DCL机制来解决缓存失效问题
            UserDO userDO = userMapper.selectById(id);

            // 缓存穿透的处理
            if (userDO == null){
                UserDTO userExitNot = new UserDTO();
                userExitNot.setUserId(-1L);
                redisUtil.set(userInfoKey, userExitNot, 10, TimeUnit.MINUTES);
                log.debug("缓存穿透处理，保存空对象至redis中。userID:{}", id);
                return null;
            }

            // 将查询的数据在redis中保存   缓存与数据一致性保证 直接简单处理 设置过期时间
            userDTO = ConvertBeanUtils.convert(userDO, UserDTO.class);
            redisUtil.set(userInfoKey, userDTO, 30, TimeUnit.MINUTES);
        }

        // 刷新该用户的过期时间 保证热点数据尽量不过期
        redisUtil.expire(userInfoKey, 30, TimeUnit.MINUTES);
        return userDTO;
    }
}
